using System.IO;
using System.Web.Services;
using System.Web.Services.Protocols;

/// <summary>
/// Implements ASP unhandled exception manager as a SoapExtension
/// </summary>
/// <remarks>
/// to use:
/// 
///    1) place ASPUnhandledException.dll in the \bin folder
///    2) add this section to your Web.config under the &lt;webServices&gt; element:
///			&lt;!-- Adds our error handler to the SOAP pipeline. --&gt;
///		    &lt;soapExtensionTypes&gt;
///				&lt;add type="ASPUnhandledException.UehSoapExtension, ASPUnhandledException"
///				     priority="1" group="0" /&gt;
///			&lt;/soapExtensionTypes&gt;
///
///  Jeff Atwood
///  http://www.codinghorror.com/
/// </remarks>
public class UehSoapExtension : SoapExtension
{
	private Stream _OldStream = null;
	private Stream _NewStream = null;

	public override object GetInitializer( System.Type serviceType )
	{
		return null;
	}
	public override object GetInitializer( LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute )
	{
		return null;
	}
	public override void Initialize( object initializer )
	{
	}

	public override Stream ChainStream( Stream stream )
	{
		_OldStream = stream;
		_NewStream = new MemoryStream();
		return _NewStream;
	}

	private void Copy( Stream fromStream, Stream toStream )
	{
		using( StreamReader sr = new StreamReader( fromStream ) )
		{
			using( StreamWriter sw = new StreamWriter( toStream ) )
			{
				sw.Write( sr.ReadToEnd() );
				sw.Flush();
			}
		}
	}

	public override void ProcessMessage( SoapMessage message )
	{
		switch( message.Stage )
		{
		case SoapMessageStage.BeforeDeserialize:
			Copy( _OldStream, _NewStream );
			_NewStream.Position = 0;
			break;

		case SoapMessageStage.AfterSerialize:
			if( message.Exception != null )
			{
				// handle our exception, and get the SOAP <detail> string
				string strDetailNode = WebExceptionHandler.HandleWebServiceException( message );
				// read the entire SOAP message stream into a string
				_NewStream.Position = 0;
				TextReader tr = new StreamReader( _NewStream );
				// insert our exception details into the string
				string s = tr.ReadToEnd();
				s = s.Replace( "<detail />", strDetailNode );
				// overwrite the stream with our modified string
				_NewStream = new MemoryStream();
				TextWriter tw = new StreamWriter( _NewStream );
				tw.Write( s );
				tw.Flush();
			}
			_NewStream.Position = 0;
			Copy( _NewStream, _OldStream );
			break;
		}
	}
}